#include "light.hpp"
#include "system.hpp"

#include "apm32f0xx_gpio.h"
#include "apm32f0xx_tmr.h"
#include "apm32f0xx_rcm.h"
static const struct {
    GPIO_T *port_light;
    PeripheralClock_t port_light_clk;
    PeripheralClock_t tmr_clk;
    PeripheralClock_t syscfg_clk;
    GPIO_PIN_T pin_red;
    GPIO_PIN_T pin_green;
    GPIO_PIN_T pin_blue;
    TMR_T *tmr_out;
}__hardware_description = {
    .port_light = GPIOC,
    .port_light_clk = CLK_GPIOC,
    .tmr_clk = CLK_TMR3,
    .syscfg_clk = CLK_SYSCFG,
    .pin_red = GPIO_PIN_7,
    .pin_green = GPIO_PIN_6,
    .pin_blue = GPIO_PIN_8,
    .tmr_out = TMR3,
};

bool _Light::init(){
    TMR_TimeBase_T  timeBaseConfig;
    TMR_OCConfig_T  occonfig;
    GPIO_Config_T   gpioconfig;

    /* Enable Clock */
    System_setPeripheralClockEnable(__hardware_description.port_light_clk,TRUE);
    System_setPeripheralClockEnable(__hardware_description.syscfg_clk,TRUE);
    System_setPeripheralClockEnable(__hardware_description.tmr_clk,TRUE);

    GPIO_ConfigPinAF(__hardware_description.port_light, GPIO_PIN_SOURCE_6, GPIO_AF_PIN0);
    GPIO_ConfigPinAF(__hardware_description.port_light, GPIO_PIN_SOURCE_7, GPIO_AF_PIN0);
    GPIO_ConfigPinAF(__hardware_description.port_light, GPIO_PIN_SOURCE_8, GPIO_AF_PIN0);
    gpioconfig.mode  = GPIO_MODE_AF;
    gpioconfig.outtype = GPIO_OUT_TYPE_PP;
    gpioconfig.pin   = __hardware_description.pin_green;
    gpioconfig.pupd  = GPIO_PUPD_NO;
    gpioconfig.speed = GPIO_SPEED_50MHz;
    GPIO_Config(__hardware_description.port_light, &gpioconfig);
    gpioconfig.pin   = __hardware_description.pin_red;
    GPIO_Config(__hardware_description.port_light, &gpioconfig);
    gpioconfig.pin   = __hardware_description.pin_blue;
    GPIO_Config(__hardware_description.port_light, &gpioconfig);

    timeBaseConfig.clockDivision =  TMR_CKD_DIV1;
    timeBaseConfig.counterMode =  TMR_COUNTER_MODE_UP;
    timeBaseConfig.div = 47;
    timeBaseConfig.period = 999;
    timeBaseConfig.repetitionCounter =  0;
    TMR_ConfigTimeBase(__hardware_description.tmr_out, &timeBaseConfig);

    occonfig.OC_Mode =  TMR_OC_MODE_PWM1;
    occonfig.OC_Idlestate  = TMR_OCIDLESTATE_RESET;
    occonfig.OC_NIdlestate = TMR_OCNIDLESTATE_RESET;
    occonfig.OC_OutputNState =  TMR_OUTPUT_NSTATE_DISABLE;
    occonfig.OC_OutputState  =  TMR_OUTPUT_STATE_ENABLE;
    occonfig.OC_Polarity  = TMR_OC_POLARITY_HIGH;
    occonfig.OC_NPolarity = TMR_OC_NPOLARITY_HIGH;
    occonfig.Pulse = 500;

    TMR_OC1Config(__hardware_description.tmr_out, &occonfig);
    TMR_OC2Config(__hardware_description.tmr_out, &occonfig);
    TMR_OC3Config(__hardware_description.tmr_out, &occonfig);
    TMR_EnablePWMOutputs(__hardware_description.tmr_out);
    TMR_Enable(__hardware_description.tmr_out);

    TMR_SetCompare1(__hardware_description.tmr_out, 500);
    TMR_SetCompare2(__hardware_description.tmr_out, 600);
    TMR_SetCompare3(__hardware_description.tmr_out, 700);

    return true;
}

void _Light::set(LightType lighttype,bool status){
    
}

bool _Light::get(LightType lighttype,bool status){

    return true;
}

void _Light::setLight(LightType lighttype,int duty){
    int compare_duty = 0;
    if( duty < 0 ) duty = 0;
    if( duty > 100 ) duty = 100;
    compare_duty = duty * 10;
    switch (lighttype){
    case LightType::Green:TMR_SetCompare1(__hardware_description.tmr_out, compare_duty);break;
    case LightType::Red:TMR_SetCompare2(__hardware_description.tmr_out, compare_duty);break;
    case LightType::Blue:TMR_SetCompare3(__hardware_description.tmr_out, compare_duty);break;
    default:break;
    }
}

static Light * light = nullptr;
Light *Light::getInstance(){
    if( light == nullptr){
        light = new _Light();
        light->init();
    }
    return light;
}
